package cn.sumpu.app.guoguojie.biz.impl;

import java.util.ArrayList;
import java.util.Collection;
import java.util.HashMap;
import java.util.LinkedHashSet;
import java.util.List;
import java.util.Map;

import javax.annotation.Resource;

import net.sf.json.JSONArray;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.security.access.ConfigAttribute;
import org.springframework.security.access.SecurityConfig;
import org.springframework.security.authentication.encoding.Md5PasswordEncoder;
import org.springframework.security.core.GrantedAuthority;
import org.springframework.security.core.authority.GrantedAuthorityImpl;
import org.springframework.transaction.annotation.Transactional;
import cn.sumpu.app.guoguojie.biz.AdminBiz;
import cn.sumpu.app.guoguojie.biz.IdentifierBiz;
import cn.sumpu.app.guoguojie.dao.AdminDao;
import cn.sumpu.app.guoguojie.domain.AdminResource;
import cn.sumpu.app.guoguojie.domain.AdminUser;
import cn.sumpu.app.guoguojie.domain.AdminRole;
import cn.sumpu.app.guoguojie.exception.AppBusinessException;
import cn.sumpu.app.guoguojie.util.Common;
import cn.sumpu.app.guoguojie.util.PageModel;

public class AdminBizImpl implements AdminBiz {

	private final static Logger logger = LoggerFactory
			.getLogger(AdminBizImpl.class);

	@Resource
	private IdentifierBiz identifierBiz;
	
	private AdminDao adminDao;

	public void setAdminDao(AdminDao adminDao) {
		this.adminDao = adminDao;
	}

	@Override
	public Collection<GrantedAuthority> loadUserAuthoritiesByUsername(
			String username) throws AppBusinessException {
		try {
			List<GrantedAuthority> auths = new ArrayList<GrantedAuthority>();
			List<AdminRole> list = adminDao.getUserAuthorityList(username);
			for (AdminRole auth : list) {
				GrantedAuthorityImpl authority = new GrantedAuthorityImpl(
						auth.getName());
				auths.add(authority);
			}
			return auths;
		} catch (Exception re) {
			if (logger.isErrorEnabled()) {
				logger.error("Find user's authorities by username failed.", re);
			}
			throw new AppBusinessException(re);
		}
	}

	@Override
	public AdminUser loadUserByUsername(String username)
			throws AppBusinessException {
		return adminDao.getUserByUsername(username);
	}

	@Override
	public Collection<ConfigAttribute> loadAllConfigAttribute()
			throws AppBusinessException {
		// 在Web服务器启动时，提取系统中的所有权限
		List<AdminRole> auths = adminDao.getAuthorityList();
		Collection<ConfigAttribute> cfList = new ArrayList<ConfigAttribute>();
		for (AdminRole auth : auths) {
			ConfigAttribute ca = new SecurityConfig(auth.getName());
			cfList.add(ca);
		}
		return cfList;
	}

	@Override
	public Map<String, Collection<ConfigAttribute>> loadResourceDefine()
			throws AppBusinessException {
		// 在Web服务器启动时，提取系统中的所有权限
		List<AdminRole> auths = adminDao.getAuthorityList();

		// 应当是资源为key， 权限为value。 资源通常为url， 权限就是那些以ROLE_为前缀的角色。 一个资源可以由多个权限来访问
		Map<String, Collection<ConfigAttribute>> resourceMap = new HashMap<String, Collection<ConfigAttribute>>();

		for (AdminRole auth : auths) {
			ConfigAttribute ca = new SecurityConfig(auth.getName());

			List<AdminResource> res = adminDao
					.getResourceListByAuthorityName(auth.getName());

			for (AdminResource re : res) {
				String url = re.getValue();

				// 判断资源文件和权限的对应关系，如果已经存在相关的资源url，则要通过该url为key提取出权限集合，将权限增加到权限集合中
				if (resourceMap.containsKey(url)) {

					Collection<ConfigAttribute> value = resourceMap.get(url);
					value.add(ca);
					resourceMap.put(url, value);
				} else {
					Collection<ConfigAttribute> atts = new ArrayList<ConfigAttribute>();
					atts.add(ca);
					resourceMap.put(url, atts);
				}

			}

		}
		return resourceMap;
	}

	// 分页查询用户信息
	@Override
	public PageModel getAdminUserList(Integer pagesize, Integer page) throws AppBusinessException {
		if(page == null || page < 1){
			page = 1;
		}
		if(pagesize == null || pagesize < 1){
			pagesize = 10;
		}
		Map<String, Object> map = new HashMap<String, Object>();
		map.put("startId", (page - 1) * pagesize);
		map.put("pageSize", pagesize);
		int count = adminDao.getAdminUserCount(map);
		PageModel pm = new PageModel();
		pm.setCurrentPage(page);
		pm.setList(adminDao.getUserList(map));
		pm.setPageSize(pagesize);
		pm.setTotalRecord(count);
		pm.setTotalPage((count + pagesize - 1)
				/ pagesize);
		return pm;
	}

	// 删除User信息
	@Override
	@Transactional(rollbackForClassName = { "cn.sumpu.app.guoguojie.exception.AppBusinessException" }, timeout = 10)
	public void deleteUser(String userId) throws AppBusinessException {
		adminDao.deleteUserRoleByUserId(userId);
		adminDao.deleteUserById(userId);
	}

	// 分页查询角色信息
	@Override
	public PageModel getAdminRoleList(Integer pagesize, Integer page) throws AppBusinessException {
		if(page ==null || pagesize < 1){
			page = 1;
		}
		if(pagesize ==null || pagesize < 1){
			pagesize = 10;
		}
		Map<String, Object> map = new HashMap<String, Object>();
		map.put("startId", (page - 1) * pagesize);
		map.put("pageSize", pagesize);
		int count = adminDao.getAdminRoleCount(map);
		PageModel pm = new PageModel();
		pm.setCurrentPage(page);
		pm.setList(adminDao.getAdminRoleList(map));
		pm.setPageSize(pagesize);
		pm.setTotalRecord(count);
		pm.setTotalPage((count + pagesize - 1)
				/ pagesize);
		return pm;
	}

	@Override
	public List<AdminRole> getAdminRole() throws AppBusinessException {
		List<AdminRole> roles = adminDao.getAdminRole();
		return roles;
	}

	@Override
	public List<AdminRole> getAdminUserRole(String id) throws AppBusinessException {
		List<AdminRole> roles = adminDao.getAdminUserRole(id);
		return roles;
	}

	@Override
	public void insertUser(AdminUser user) throws AppBusinessException {
		String identifier = identifierBiz.generateId("account");
		user.setIdentifier(identifier);
		user.setPassword(new Md5PasswordEncoder().encodePassword(user.getPassword(), user.getUsername()));
		adminDao.insertUser(user);
	}

	// 更新用户和角色的绑定关系
	@Override
	@Transactional(rollbackForClassName = { "cn.sumpu.app.guoguojie.exception.AppBusinessException" }, timeout = 10)
	public void updateUserRole(String arrRoleList, String userId)
			throws AppBusinessException {

		adminDao.deleteUserRoleByUserId(userId);

		JSONArray arrRoleArray = JSONArray.fromObject(arrRoleList);
		@SuppressWarnings({ "static-access", "unchecked" })
		ArrayList<String> list = (ArrayList<String>) arrRoleArray.toCollection(arrRoleArray, String.class);
		list = new ArrayList<String>(new LinkedHashSet<String>(list));	//去重
		for (String str: list) {
			insertUserRoleId(str, userId);
		}
	}

	// 插入选择的role
	@Override
	public void insertUserRoleId(String roleId, String userId)
			throws AppBusinessException {
		Map<String, Object> map = new HashMap<String, Object>();
		map.put("userId", userId);
		map.put("roleId", roleId);
		adminDao.insertUserRoleId(map);
	}

	// 查询role对应的资源集合
	@Override
	public List<AdminResource> getAdminResource() throws AppBusinessException {
		List<AdminResource> resources = adminDao.getAdminResource();
		return resources;
	}

	@Override
	public List<AdminResource> getAdminRoleResource(String id)
			throws AppBusinessException {
		List<AdminResource> resources = adminDao.getAdminRoleResource(id);
		return resources;
	}

	// 更新角色和资源的绑定关系
	@Override
	@Transactional(rollbackForClassName = { "cn.sumpu.app.guoguojie.exception.AppBusinessException" }, timeout = 10)
	public void updateRoleResource(String arrResourceList, String roleId)
			throws AppBusinessException {

		adminDao.deleteRoleResourceByRoleId(roleId);

		JSONArray arrResourceArray = JSONArray.fromObject(arrResourceList);
		@SuppressWarnings({ "static-access", "unchecked" })
		ArrayList<String> list = (ArrayList<String>) arrResourceArray.toCollection(arrResourceArray, String.class);
		list = new ArrayList<String>(new LinkedHashSet<String>(list));	//去重
		for (String str: list) {
			insertUserResourceId(str, roleId);
		}
	}

	// 插入选择的role
	@Override
	public void insertUserResourceId(String resourceId, String roleId)
			throws AppBusinessException {
		Map<String, Object> map = new HashMap<String, Object>();
		map.put("resourceId", resourceId);
		map.put("roleId", roleId);
		adminDao.insertUserResourceId(map);
	}

	// 分页查询资源信息
	@Override
	public PageModel getAdminResourceList(Integer pagesize, Integer page)
			throws AppBusinessException {
		if(page == null || page < 1){
			page = 1;
		}
		if(pagesize == null || pagesize < 1){
			pagesize = 10;
		}
		Map<String, Object> map = new HashMap<String, Object>();
		map.put("startId", (page - 1) * pagesize);
		map.put("pageSize", pagesize);
		int count = adminDao.getAdminResourceCount(map);
		PageModel pm = new PageModel();
		pm.setCurrentPage(page);
		pm.setList(adminDao.getAdminResourceList(map));
		pm.setPageSize(pagesize);
		pm.setTotalRecord(count);
		pm.setTotalPage((count + pagesize - 1)
				/ pagesize);
		return pm;
	}

	@Override
	@Transactional(rollbackForClassName = { "cn.sumpu.app.guoguojie.exception.AppBusinessException" }, timeout = 10)
	public void deleteResource(String resourceId) throws AppBusinessException {
		adminDao.deleteRoleResourceByResourceId(resourceId);
		adminDao.deleteResourceById(resourceId);
	}

	@Override
	public void insertResource(AdminResource resource)
			throws AppBusinessException {
		String identifier = identifierBiz.generateId("admin_resource");
		resource.setIdentifier(identifier);
		adminDao.insertResource(resource);
	}

	@Override
	public void insertRole(AdminRole role) throws AppBusinessException {
		String identifier = identifierBiz.generateId("admin_role");
		role.setIdentifier(identifier);
		adminDao.insertRole(role);
	}

	@Override
	@Transactional(rollbackForClassName = { "cn.sumpu.app.guoguojie.exception.AppBusinessException" }, timeout = 10)
	public void deleteRole(String roleId) throws AppBusinessException {
		adminDao.deleteUserRoleByRoleId(roleId);
		adminDao.deleteRoleResourceByRoleId(roleId);
		adminDao.deleteRoleById(roleId);
	}

	@Override
	public void updateUser(AdminUser user) throws AppBusinessException {
		if(Common.notEmptyStr(user.getPassword())){
			user.setPassword(new Md5PasswordEncoder().encodePassword(user.getPassword(), user.getUsername()));
		}
		adminDao.updateUser(user);
	}

	@Override
	public void updateRole(AdminRole role) throws AppBusinessException {
		adminDao.updateRole(role);
	}

	@Override
	public void updateResource(AdminResource resource)
			throws AppBusinessException {
		adminDao.updateResource(resource);
	}

	@Override
	public AdminUser getUserById(String id) throws AppBusinessException {
		return adminDao.getUserById(id);
	}

	@Override
	public AdminRole getRoleById(String id) throws AppBusinessException {
		return adminDao.getRoleById(id);
	}

	@Override
	public AdminResource getResourceById(String id) throws AppBusinessException {
		return adminDao.getResourceById(id);
	}

}
